package cn.edu.zisu.common.util.annotaion.interceptor;

import cn.edu.zisu.common.model.enumeration.BaseEnum;
import cn.edu.zisu.common.util.annotaion.DeserializerAnnotation;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author ymf
 * @date 2020/3/19
 */
public class JsonDeserializerInterceptor extends JsonDeserializer<Object> implements ContextualDeserializer {

    private static final ZoneOffset CTT = OffsetDateTime.now(ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))).getOffset();
    private static final String SEPARATE = ",";

    private Class<?> clazz;

    private Class<?> listValue;

    public JsonDeserializerInterceptor() {
    }

    public JsonDeserializerInterceptor(Class<?> clazz, Class<?> listValue) {
        this.clazz = clazz;
        this.listValue = listValue;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
        try {
            if (jsonParser != null && StringUtils.isNotEmpty(jsonParser.getText())) {
                if (clazz == LocalDateTime.class) {
                    return LocalDateTime.ofInstant(Instant.ofEpochMilli(jsonParser.getLongValue()), CTT);
                } else if (clazz == LocalDate.class) {
                    return LocalDateTime.ofInstant(Instant.ofEpochMilli(jsonParser.getLongValue()), CTT).toLocalDate();
                } else if (BaseEnum.class.isAssignableFrom(clazz)) {
                    Class<? extends BaseEnum> type = (Class<? extends BaseEnum>) clazz;
                    for (BaseEnum baseEnum : type.getEnumConstants()) {
                        if (baseEnum.getValue() == jsonParser.getIntValue()) {
                            return baseEnum;
                        }
                    }
                    return null;
                } else if (List.class.isAssignableFrom(clazz)) {
                    String str = jsonParser.getText();
                    if (StringUtils.isEmpty(str)) {
                        return null;
                    }
                    String[] list = str.split(SEPARATE);
                    if (listValue == LocalDateTime.class) {
                        return Arrays.stream(list).map(o -> LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(o)), CTT)).collect(Collectors.toList());
                    } else if (listValue == LocalDate.class) {
                        return Arrays.stream(list).map(o -> LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(o)), CTT).toLocalDate()).collect(Collectors.toList());
                    } else if (BaseEnum.class.isAssignableFrom(listValue)) {
                        List<BaseEnum> result = Lists.newArrayList();
                        for (String o : list) {
                            Class<? extends BaseEnum> type = (Class<? extends BaseEnum>) listValue;
                            for (BaseEnum baseEnum : type.getEnumConstants()) {
                                if (Objects.equals(baseEnum.getValue(), Integer.valueOf(o))) {
                                    result.add(baseEnum);
                                }
                            }
                        }
                        return result;
                    }
                    return null;
                } else {
                    return jsonParser.getText();
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new RuntimeException("反序列化失败", e);
        }
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            DeserializerAnnotation deserializerAnnotation = beanProperty.getAnnotation(DeserializerAnnotation.class);
            if (deserializerAnnotation == null) {
                deserializerAnnotation = beanProperty.getContextAnnotation(DeserializerAnnotation.class);
            }
            if (deserializerAnnotation != null) {
                return new JsonDeserializerInterceptor(beanProperty.getType().getRawClass(), deserializerAnnotation.listValue());
            }
            return deserializationContext.findNonContextualValueDeserializer(beanProperty.getType());
        }
        return this;
    }
}